// RegistryIndexer: Build in-memory index of installed apps via Windows registry
// Sources:
// - HKLM/HKCU \SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths
// - HKLM/HKCU/WOW6432Node \SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall
// Extract executable paths from default/App Paths and from Uninstall DisplayIcon

const { execFileSync } = require('child_process')
const path = require('path')
const fs = require('fs')

function runReg(args) {
  try {
    const out = execFileSync('reg', args, { encoding: 'utf8' })
    return out
  } catch (_) {
    return ''
  }
}

function listSubKeys(root) {
  // reg query <root>
  const out = runReg(['query', root])
  const lines = out.split(/\r?\n/).map(l => l.trim()).filter(Boolean)
  const subs = []
  for (const l of lines) {
    // Lines that are full subkey paths start with HK*
    if (/^HKEY_/i.test(l) && l.toLowerCase().startsWith(root.toLowerCase())) {
      subs.push(l)
    }
  }
  return subs
}

function readValues(keyPath) {
  const out = runReg(['query', keyPath])
  const lines = out.split(/\r?\n/)
  const values = {}
  for (const line of lines) {
    // Format: <ValueName>    <Type>    <Data>
    // ValueName might be '(默认)' or '(Default)'
    const m = line.match(/^\s*(.+?)\s+REG_\w+\s+(.*)$/)
    if (m) {
      const name = m[1].trim()
      const data = m[2].trim()
      const norm = (name === '(默认)' || name === '(Default)') ? 'default' : name
      values[norm] = data
    }
  }
  return values
}

function sanitizeExePath(p) {
  if (!p) return ''
  // Remove trailing arguments or icon index after comma
  // e.g., "C:\\Program Files\\App\\app.exe,0" => exe path
  const commaIdx = p.toLowerCase().indexOf('.exe,')
  if (commaIdx >= 0) {
    return p.slice(0, commaIdx + 4)
  }
  // If contains quotes, take inside
  const quoted = p.match(/"([^"]+\.exe)"/i)
  if (quoted) return quoted[1]
  // If contains .exe somewhere, trim after .exe
  const exeIdx = p.toLowerCase().indexOf('.exe')
  if (exeIdx >= 0) return p.slice(0, exeIdx + 4)
  return p
}

class RegistryIndexer {
  constructor() {
    this.items = [] // { id,name,path,type:'app', lastUpdated }
  }

  buildIndex() {
    const now = Date.now()
    const indexed = []

    // App Paths: HKLM/HKCU
    const appPathsRoots = [
      'HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths',
      'HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths',
    ]
    for (const root of appPathsRoots) {
      const subs = listSubKeys(root)
      for (const sub of subs) {
        const values = readValues(sub)
        const exePath = sanitizeExePath(values.default || values.Path || '')
        if (exePath && exePath.toLowerCase().endsWith('.exe') && fs.existsSync(exePath)) {
          const name = path.basename(exePath, '.exe')
          indexed.push({ id: sub, name, path: exePath, type: 'app', lastUpdated: now })
        }
      }
    }

    // Uninstall entries: HKLM/HKCU + WOW6432Node
    const uninstallRoots = [
      'HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall',
      'HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall',
      'HKLM\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall',
    ]
    for (const root of uninstallRoots) {
      const subs = listSubKeys(root)
      for (const sub of subs) {
        const values = readValues(sub)
        const displayName = values.DisplayName || ''
        let exePath = sanitizeExePath(values.DisplayIcon || '')
        if (!exePath && values.InstallLocation) {
          // Try common exe name from install location: <DisplayName>.exe
          const candidate = path.join(values.InstallLocation, `${displayName}.exe`)
          if (displayName && fs.existsSync(candidate)) exePath = candidate
        }
        if (exePath && exePath.toLowerCase().endsWith('.exe') && fs.existsSync(exePath)) {
          const name = displayName || path.basename(exePath, '.exe')
          indexed.push({ id: sub, name, path: exePath, type: 'app', lastUpdated: now })
        }
      }
    }

    // Deduplicate by name|path
    const uniq = new Map()
    for (const it of indexed) {
      const key = `${(it.name || '').toLowerCase()}|${it.path.toLowerCase()}`
      if (!uniq.has(key)) uniq.set(key, it)
    }
    this.items = Array.from(uniq.values())
    return this.items
  }

  getAll() { return this.items }
}

module.exports = { RegistryIndexer }
